package org.jeecg.modules.dzswj;

import cn.hutool.json.XML;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.dzswj.exception.SmdlException;
import org.jeecg.modules.dzswj.vo.LoginSessionVo;
import org.jeecg.modules.dzswj.vo.request.*;
import org.jeecg.modules.dzswj.vo.response.CxnsrysbjlResponseVo;
import org.jeecg.modules.dzswj.vo.response.DzswjBaseResponse;
import org.jeecg.modules.dzswj.vo.response.PzjgxxVo;
import org.jeecg.modules.dzswj.vo.response.SmzdlResponseVo;
import org.jeecg.modules.dzswj.vo.response.cwbb.GsCwbbVo;
import org.jeecg.modules.dzswj.vo.response.fpxx.DzdzfpbccxVo;
import org.jeecg.modules.dzswj.vo.response.fpxx.DzdzplFpxxcxResponseVo;
import org.jeecg.modules.dzswj.vo.response.fpxx.DzdzqdcxVo;
import org.jeecg.modules.dzswj.vo.response.fpxx.FpBaseResponse;
import org.jeecg.modules.dzswj.vo.response.nsrxxcx.Kzxx;
import org.jeecg.modules.dzswj.vo.response.nsrxxcx.Nsrjbxx;
import org.jeecg.modules.dzswj.vo.response.nsrxxcx.NsrxxCxResponseVo;
import org.jeecg.modules.fk.entity.DjOrg;
import org.jeecg.modules.fk.service.IDjOrgService;
import org.jeecg.modules.qyxx.entity.DjNsrxxPO;
import org.jeecg.modules.qyxx.service.IDjNsrxxService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 广东三方接入
 * @author chensherun on 2022/2/21.
 * @version 1.0
 */
@Service
@Slf4j
public class GuangdongSfjrApiService {

    //接口地址
    @Value("${dzswj.guangdong.sfjr.address:}")
    private String address;
    //用户名
    @Value("${dzswj.guangdong.sfjr.userName:}")
    private String userName;
    //密码
    @Value("${dzswj.guangdong.sfjr.password:}")
    private String password;
    //供应商ID
    @Value("${dzswj.guangdong.sfjr.supplierId:}")
    private String supplierId;
    //应用ID
    @Value("${dzswj.guangdong.sfjr.applicationId:}")
    private String applicationId;
    //服务版本
    @Value("${dzswj.guangdong.sfjr.version:}")
    private String version;
    //认证类型 1证书，2用户密码
    @Value("${dzswj.guangdong.sfjr.authenticateType:}")
    private String authenticateType;
    //是否使用新密码规则 true：使用 false：不使用
    @Value("${dzswj.guangdong.sfjr.isNewPsw:true:}")
    private boolean isNewPsw;
    //密码加密key
    @Value("${dzswj.guangdong.sfjr.pswkey:}")
    private String pswkey;
    @Value("${dzswj.guangdong.sfjr.defaultUsername:}")
    private String defaultUsername;
    @Value("${dzswj.guangdong.sfjr.defaultPassword:}")
    private String defaultPassword;

    @Autowired
    private IDjOrgService djOrgService;

    @Autowired
    private IDjNsrxxService nsrxxService;

    @Autowired
    private RedisUtil redisUtil;

    public final static String DB_PASS_KEY = "ZC2022!@#$%";

    //纳税人登录会话信息
    final static String SFJR_NSR_SESSION_INFO = "sfjr:loginInfo:sessionInfo:";
    final static String AREA_CODE = "440000";
//    //登录会话ID
//    final static String SFJR_NSR_SESSION_ID = "sfjr:loginInfo:sessionId:";
//    //纳税人税种机关代码
//    final static String SFJR_NSR_SWJGDM = "sfjr:loginInfo:swjgDm:";
//    //纳税人登记序号
//    final static String SFJR_NSR_DJXH = "sfjr:loginInfo:djxh:";

    //session缓存时间,设置为20分钟
    final static Long sessionIdLifeTime = 1200L;

    //调用接口
    private Result<String> dy(String sessionId, String sid, String swjgDm, String content) {
        String resStr = "";
        Base64 base64 = new Base64();
        //调用（发起接口调用）
        String reqXml = getReqXml(sessionId, sid, swjgDm, content);

        //返回接口报文
        String resXml = null;
        try {
            resXml = httpClientPost(reqXml);
        } catch (Exception e) {
            log.error("调用错误",e);
            return new Result<String>().error500("调用三方接口失败，网络异常");
        }

        if (null != resXml) {
            //处理返回报文
            resXml = getBizXml(resXml);
            resXml = transfer(resXml);
            //解析返回报文
            VtdXmlOperateDelegate delegate = new VtdXmlOperateDelegate(resXml);
            String returnCode = delegate.getNodeDataByXpath("/service/head/rtn_code");
            System.out.println(returnCode);
            //returnCode返回"0"认为接口调用成功
            if ("000".equals(returnCode) || "0".equals(returnCode)) {
                //得到content
                resStr = delegate.getNodeDataByXpath("/service/body");
                return Result.OK("成功", resStr);
            } else {
                String message = delegate.getNodeDataByXpath("/service/head/rtn_msg/Message");
                String reason = delegate.getNodeDataByXpath("/service/head/rtn_msg/Reason");
                log.error("调用接口{}失败，失败信息：{}，原因：{}", sid, message, reason);
                return new Result<String>().error500("调用失败:" + message + "," + reason);
            }
        } else {
            log.error("调用接口" + sid + "失败，失败信息：返回报文为空");
            return new Result<String>().error500("返回报文为空");
        }
    }

    //调用接口
    private Result<String> dyNsrxxCx(String sessionId, String sid, String swjgDm, String content) {
        String resStr = "";
        Base64 base64 = new Base64();
        byte[] contentEncode = base64.encode(content.getBytes());
        //调用（发起接口调用）
        String reqXml = getReqXml(sessionId, sid, swjgDm, content);

        //返回接口报文
        String resXml = null;
        try {
            resXml = httpClientPost(reqXml);
        } catch (Exception e) {
            log.error("调用错误",e);
            return new Result<String>().error500("调用三方接口失败，网络异常");
        }

        if (null != resXml) {
            log.info("返回报文：" + resXml);
            //处理返回报文
            resXml = getBizXml(resXml);
            resXml = transfer(resXml);
            //解析返回报文
            VtdXmlOperateDelegate delegate = new VtdXmlOperateDelegate(resXml);
            String returnCode = delegate.getNodeDataByXpath("/taxML/bizContent/bizResult/head/rtnCode");
            //returnCode返回"0"认为接口调用成功
            if ("000".equals(returnCode) || "0".equals(returnCode)) {
                //得到content
                resStr = delegate.getNodeDataByXpath("/taxML/bizContent/bizResult/body");
                return Result.OK("成功", resStr);
            } else {
                String message = delegate.getNodeDataByXpath("/taxML/bizContent/bizResult/head/rtnMsg/Message");
                String returnStateCode = delegate.getNodeDataByXpath("/taxML/returnState/returnCode");
                String returnStateMessage = delegate.getNodeDataByXpath("/taxML/returnState/returnMessage");
                String errorMsg = String.format("调用查询纳税人信息接口%s失败，失败信息：%s, returnStateCode:%s, returnStateMessage:%s", sid, message, returnStateCode, returnStateMessage);
                log.error(errorMsg);
                return new Result<String>().error500(errorMsg);
            }
        } else {
            log.error("调用接口" + sid + "失败，失败信息：返回报文为空");
            return new Result<String>().error500("调用接口出错，返回报文为空");
        }
    }

    //调用接口
    private Result<String> dycwbb(String sessionId, String sid, String swjgDm, String content) {
        String resBizXml = "";
        Base64 base64 = new Base64();
        byte[] contentEncode = base64.encode(content.getBytes());
        //调用（发起接口调用）
        String reqXml = getReqXml(sessionId, sid, swjgDm, content);

        //返回接口报文
        String resXml = null;
        try {
            resXml = httpClientPost(reqXml);
        } catch (Exception e) {
            log.error("调用错误",e);
            return new Result<String>().error500("调用三方接口失败，网络异常");
        }

        if (null != resXml) {
            log.debug("返回报文：" + resXml);
            //处理返回报文
            resXml = getBizXml(resXml);
            resXml = transfer(resXml);

            //解析返回报文
            VtdXmlOperateDelegate delegate = new VtdXmlOperateDelegate(resXml);
            //有可能出错
            if (resXml.startsWith("<service")) {
                String returnCode = delegate.getNodeDataByXpath("/service/head/rtn_code");
                if (!"000".equals(returnCode) && !"0".equals(returnCode)) {
                    String message = delegate.getNodeDataByXpath("/service/head/rtn_msg/Message");
                    log.error("调用接口" + sid + "失败，失败信息：" + message);
                    return new Result<String>().error500("调用接口" + sid + "失败，失败信息：" + message);
                }
            }

            String returnCode = delegate.getNodeDataByXpath("/taxML/bizContent/bizResult/head/rtnCode");
            log.debug("接口返回状态码:" + returnCode);
            //returnCode返回"0"认为接口调用成功
            if ("000".equals(returnCode) || "0".equals(returnCode)) {
                //得到content
                resBizXml = delegate.getNodeDataByXpath("/taxML/bizContent/bizResult/body");
                VtdXmlOperateDelegate delegate2 = new VtdXmlOperateDelegate(resBizXml);
                resBizXml = delegate2.getNodeDataByXpath("/taxML/res");
                return Result.OK(resBizXml);
            } else {
                String message = delegate.getNodeDataByXpath("/service/head/rtnMsg/Message");
                log.error("调用接口" + sid + "失败，失败信息：" + message);
                return new Result<String>().error500("调用接口" + sid + "失败，失败信息：" + message);
            }
        } else {
            log.error("调用接口" + sid + "失败，失败信息：返回报文为空");
            return new Result<String>().error500("调用接口出错，返回报文为空");
        }
    }

    //获取完整报文
    public String getBizXml(String str) {
        if (null != str) {
            str = str.substring(str.indexOf("<return>") + "</return>".length() - 1, str.indexOf("</return>"));
        }
        return str;
    }

    //特殊字符转换
    public String transfer(String str) {
        if (null != str) {
            str = str.replace("&lt;", "<");
            str = str.replace("&gt;", ">");
            str = str.replace("&amp;", "&");
        }
        return str;
    }

    //HttpClient方式发起请求
    public String httpClientPost(String str) throws Exception {
        HttpClient httpClient = new HttpClient();
        PostMethod postMethod = new PostMethod(address);
        InputStream inputStream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
        RequestEntity requestEntity = new InputStreamRequestEntity(inputStream, str.length(), "application/soap+xml; charset=utf-8");
        postMethod.setRequestEntity(requestEntity);

        int state = httpClient.executeMethod(postMethod);

        String result = "";
        InputStream soapResponseStream = postMethod.getResponseBodyAsStream();
        InputStreamReader inputStreamReader = new InputStreamReader(soapResponseStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        String responseLine = "";
        while ((responseLine = bufferedReader.readLine()) != null) {
            result = result + responseLine;
        }
        if (state != 200) {
            throw new JeecgBootException("调用接口异常, state:" + state);
        }
        return result;
    }

    //组装请求报文
    public String getReqXml(String sessionId, String sid, String swjgDm, String content) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String tranReqDate = sdf.format(new Date());

        //生成tranSeq
        String tranSeq = TidGenerator.generateTranseq(userName, "", swjgDm);

        String psw = password;
        if (isNewPsw) {
            pswkey = pswkey == null || "".equals(pswkey) ? "foresee2018" : pswkey;
            psw = psw + "_" + System.currentTimeMillis();

            try {
                psw = DESUtil.encrypt(psw, pswkey);
            } catch (Exception e) {
                log.error("加密密码失败", e);
                e.printStackTrace();
            }
        }

        //组装请求报文
        String str = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:cn=\"http://cn.gov.chinatax.gt3nf.service/\">\n" +
                "   <soapenv:Header>\n" +
                "      <wsse:Security soapenv:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">\n" +
                "         <wsse:UsernameToken wsu:Id=\"UsernameToken-D3378B7FD81742432114955205452374\">\n" +
                "           <wsse:Username>"+userName+"</wsse:Username>\n" +
                "            <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">" + psw +"</wsse:Password>\n" +
                "         </wsse:UsernameToken>\n" +
                "      </wsse:Security>\n" +
                "   </soapenv:Header>\n" +
                "   <soapenv:Body>\n" +
                "      <cn:doService>\n" +
                "         <bizXml><![CDATA[<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "            <tiripPackage xsi:type=\"tiripPackage\" \n" +
                "                xmlns:xsi=\"http://www.w3.org/2001/XMLSchema \" \n" +
                "                xmlns=\"http://www.chinatax.gov.cn/dataspec/ \">\n" +
                "                <sessionId>"+ sessionId +"</sessionId>\n" +
                "                <service>\n" +
                "                    <serviceId>" + sid + "</serviceId>\n" +
                "                    <clientNo/>\n" +
                "                    <tranSeq>"+tranSeq+"</tranSeq>\n" +
                "                    <repeatFlag>0</repeatFlag>\n" +
                "                    <tranReqDate>" + tranReqDate + "</tranReqDate>\n" +
                "                </service>\n" +
                "                <identity>\n" +
                "                   <application>\n" +
                "                        <applicationId>" + applicationId + "</applicationId>\n" +
                "                        <supplier>"+ supplierId + "</supplier>\n" +
                "                        <version>"+ "1" +"</version>\n" +
                "                        <authenticateType>"+ authenticateType +"</authenticateType>\n" +
                "                        <password/>\n" +
                "                        <cert/>\n" +
                "                    </application>\n" +
                "                    <customer>\n" +
                "                        <customerId/>\n" +
                "                        <authenticateType>2</authenticateType>\n" +
                "                        <password/>\n" +
                "                        <cert/>\n" +
                "                        <nsrsbh/>\n" +
                "                        <djxh/>\n" +
                "                    </customer>\n" +
                "                </identity>\n" +
                "                <routerSession>\n" +
                "                    <paramList>\n" +
                "                        <name>SENDER</name>\n" +
                "                        <value/>\n" +
                "                    </paramList>\n" +
                "                </routerSession>\n" +
                "                <signData>\n" +
                "                    <signType>0</signType>\n" +
                "                    <signSource>000</signSource>\n" +
                "                    <signValue>000</signValue>\n" +
                "                </signData>\n" +
                "                <businessContent>\n" +
                "                    <subPackage>\n" +
                "                        <id>1</id>\n" +
                "                        <content>" + content + "</content>\n" +
                "                    </subPackage>\n" +
                "                </businessContent>\n" +
                "            </tiripPackage>]]></bizXml>\n" +
                "      </cn:doService>\n" +
                "   </soapenv:Body>\n" +
                "</soapenv:Envelope>";
        return str;
    }

    /**
     * 获取企业登录会话信息
     * @param nsrsbh
     */
    public LoginSessionVo getNsrLoginSessionInfo(String nsrsbh) {
        String redisKey = SFJR_NSR_SESSION_INFO + nsrsbh;
        String sessionInfo = redisUtil.getString(redisKey);
        if (StringUtils.isNotBlank(sessionInfo)) {
            LoginSessionVo loginSession = JSONObject.parseObject(sessionInfo, LoginSessionVo.class);
            if (StringUtils.isNotBlank(loginSession.getSessionId())) {
                return loginSession;
            }
        }
        //判断是否有缓存，有则直接返回，无则再用企业的账号登录
        DjOrg djOrg = djOrgService.getByNsrsbhOrShxydm(nsrsbh);
        //查询数据库dj_nsrxx
        DjNsrxxPO nsrxx = nsrxxService.getById(nsrsbh);
        if (djOrg == null || djOrg.getIsAuth() == null || djOrg.getIsAuth() != 1) {
            throw new SmdlException(SmdlException.ErrorCode.UN_AUTH, "企业未授权");
        }

        //查询纳税人的账号密码
        String yhm = djOrg.getRealYhm();
        String password = djOrg.getPassword();
        if (StringUtils.isBlank(yhm) || StringUtils.isBlank(password)) {
            yhm = defaultUsername;
            password = defaultPassword;
        }
        if (StringUtils.isNotBlank(password)) {
            try {
                password = DESUtil.decrypt(password, DB_PASS_KEY);
            } catch (Exception e) {
                log.error("解密密码出错");
            }
        }

        if (StringUtils.isBlank(yhm) || StringUtils.isBlank(password)) {
            throw new SmdlException(SmdlException.ErrorCode.UN_AUTH, "企业未授权电局账号密码");
        }

        //查询纳税人的税务机关代码
        SmzyhdlReqVo reqVo = new SmzyhdlReqVo();
        reqVo.setYhm(yhm);
        reqVo.setPassword(password);
        //登录
        SmzdlResponseVo.Body loginResponse = djyhmhmmdljk(reqVo);
        String ssoSessionId = loginResponse.getSsoSessionId();
        SmzdlResponseVo.SsoLoginInfo ssoLoginInfo = loginResponse.getSsoLoginInfo();
        List<SmzdlResponseVo.Nsr> nsrs = ssoLoginInfo.getNsrs();
        if (nsrs == null || nsrs.size() == 0) {
            throw new SmdlException(SmdlException.ErrorCode.LOGIN_FAIL, "无有绑定企业");
        }

        //如果登记信息里没有该纳税人信息，则通过接口查询
        if (nsrxx == null) {
            Set<String> djxhSet = new HashSet<>();
            for (SmzdlResponseVo.Nsr nsrVo : nsrs) {
                if ("N".equals(nsrVo.getTybz()) && (nsrsbh.equals(nsrVo.getGsnsrsbh()) || nsrsbh.equals(nsrVo.getShxydm()))) {
                    //nsr = nsrVo;
                    djxhSet.add(nsrVo.getGszdjxh());
                }
            }
            if (djxhSet.size() == 0) {
                throw new SmdlException("实名账号没有绑定该企业");
            }
            for (String djxh : djxhSet) {
                NsrxxCxResponseVo nsrxxCxResponseVoTemp = this.nsrxxCx(ssoSessionId, null, djxh);
                Nsrjbxx nsrjbxx = nsrxxCxResponseVoTemp.getNsrjbxx();
                //只保存满足条件的djxh对应的企业信息
                if ("N".equals(nsrjbxx.getKqccsztdjbz()) && Integer.valueOf(nsrjbxx.getKzztdjlxdm()) <= 1110 && "Y".equals(nsrjbxx.getYxbz())) {
                    Kzxx.Nsrjbxx nsrkzxx = nsrxxCxResponseVoTemp.getKzxx().getNsrjbxx();
                    JSONObject jbxxJson = (JSONObject) JSONObject.toJSON(nsrjbxx);
                    JSONObject nsrkzxxJson = (JSONObject) JSONObject.toJSON(nsrkzxx);
                    jbxxJson.putAll(nsrkzxxJson);
                    nsrxx = JSONObject.parseObject(JSON.toJSONString(jbxxJson), DjNsrxxPO.class);
                    nsrxx.setTynsrsbh(StringUtils.isNotBlank(nsrxx.getShxydm()) ? nsrxx.getShxydm() : nsrxx.getNsrsbh());
                    nsrxx.setGdslxDm("01");
                    nsrxx.setSjcjSj(new Date());
                    nsrxxService.saveOrUpdate(nsrxx);
                    break;
                }
            }
        }

        if (nsrxx == null) {
            throw new SmdlException(SmdlException.ErrorCode.LOGIN_FAIL, "登记纳税人信息表没有该企业" + nsrsbh);
        }

        //企业绑定ID，通过登记配置
        SmzdlResponseVo.Nsr qyxx = null;
        for (SmzdlResponseVo.Nsr nsr:nsrs) {
            if (!"N".equals(nsr.getTybz())) {
                if (nsrxx.getDjxh().equals(nsr.getGszdjxh())) {
                    qyxx = nsr;
                    break;
                }
            }
        }

        //暂时不用切换企业
/*        if (qyxx == null) {
            log.error("实名账号【{}】下没有绑定该企业【{}】", yhm, nsrsbh);
            throw new JeecgBootException("实名账号下没有绑定该企业");
        }
        //切换身份
        xzqysf(ssoSessionId, nsrxx.getZgswjDm(), qyxx.getQybdid());*/
        //将登录信息缓存到redis
        LoginSessionVo loginSessionVo = new LoginSessionVo();
        loginSessionVo.setSessionId(ssoSessionId);
        loginSessionVo.setNsrsbh(nsrsbh);
        loginSessionVo.setAreaCode(AREA_CODE);
        loginSessionVo.setZgswjdm(nsrxx.getZgswjDm());
        loginSessionVo.setDjxh(nsrxx.getDjxh());
        redisUtil.setString(redisKey, JSON.toJSONString(loginSessionVo), sessionIdLifeTime);
        return loginSessionVo;
    }

    /**
     * 实名制登录
     * @param smzyhdlReqVo
     */
    public SmzdlResponseVo.Body djyhmhmmdljk(SmzyhdlReqVo smzyhdlReqVo) {
        String swjgDm = "14401000000";

        String sid = "SWZJ.DZSWJ.SSO.DJYHMHMMDLJK";
        String request = "{body:[{yhm:\"" + smzyhdlReqVo.getYhm() + "\",password:\"" + smzyhdlReqVo.getPassword() + "\",sjly:\"0\",ip:\"127.0.0.1\",qddm:\"09\"}]}";
        String loginContent = null;
        try {

        } catch (Exception e) {
            log.error("加密请求报文出错", e);
            throw new JeecgBootException("加密请求报文出错");
        }
        Result<String> result = dy("", sid, swjgDm, loginContent);
        if (!result.isSuccess()) {
            log.error("实名账号登录接口{}出错, 请求报文：{}, 错误信息：{}", sid, request, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        //json转换
        String response = result.getResult();
        SmzdlResponseVo smzdlResponseVo = JSONObject.parseObject(response, new TypeReference<SmzdlResponseVo>() {});
        if (!"0".equals(smzdlResponseVo.getRtnCode())) {
            throw new SmdlException(SmdlException.ErrorCode.LOGIN_FAIL, smzdlResponseVo.getMessage());
        }
        if (!"0".equals(smzdlResponseVo.getBody().getReturncode())) {
            throw  new SmdlException(SmdlException.ErrorCode.LOGIN_FAIL, smzdlResponseVo.getBody().getReturnmessage());
        }
        //smzdlResponseVo.getBody().getSsoLoginInfo();
        return smzdlResponseVo.getBody();
    }

    /**
     * 选择企业
     * @param sessionId
     * @param swjgDm
     * @param qybdid
     */
    public Boolean xzqysf(String sessionId, String swjgDm, String qybdid) {
        if (StringUtils.isNotBlank(swjgDm)) {
            swjgDm = "14400000000";
        }
        String sid = "GD.QX.SSO.DZSWJCZ.xzqysf";
        String request = "{\"body\":[{\"ssoSessionId\":\"" + sessionId + "\",\"qybdid\":\"" + qybdid + "\"}]}";

        String content = null;
        try {

        } catch (Exception e) {
            log.error("加密请求报文出错", e);
            throw new JeecgBootException("加密请求报文出错");
        }
        Result<String> result = dy(sessionId, sid, swjgDm, content);
        if (!result.isSuccess()) {
            log.error("调用切换企业身份接口{}出错, 请求报文：{}, 错误信息：{}", sid, request, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        SmzdlResponseVo smzdlResponseVo = JSONObject.parseObject(result.getResult(), new TypeReference<SmzdlResponseVo>() {});
        if (!"1".equals(smzdlResponseVo.getRtnCode())) {
            throw new JeecgBootException(smzdlResponseVo.getMessage());
        }
        //{"timeStamp":"20220222102332","tranId":"","tranSeq":"dfb62516-19e7-4f48-a4ac-787fe1e605d6","code":"1","signatureInfo":"","body":{"returnmessage":"切换企业身份成功","returncode":"1"},"message":"调用成功","rtnCode":"1"}
        if (!"1".equals(smzdlResponseVo.getBody().getReturncode())) {
            throw new JeecgBootException(smzdlResponseVo.getBody().getReturnmessage());
        }
        return true;
    }

    /**
     * 查询纳税人基本信息
     * @param sessionId
     * @param swjgDm
     * @param djxh
     */
    public NsrxxCxResponseVo nsrxxCx(String sessionId, String swjgDm, String djxh) {
        if (StringUtils.isNotBlank(swjgDm)) {
            swjgDm = "14400000000";
        }
        String sid = "ETax.SB.queryNsrxxByDjxh.NsrxxCx";
        String request = "<taxML xmlns=\"http://www.chinatax.gov.cn/gt3nf\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"sbCommonCshReq\" cnName=\"\" name=\"sbCommonCshReq\" version=\"SW5001-2006\">\n" +
                "\t<djxh>$djxh</djxh>\n" +
                "</taxML>";
        String content = request.replace("$djxh", djxh);
        Result<String> result = dyNsrxxCx(sessionId, sid, swjgDm, content);
        if (!result.isSuccess()) {
            log.error("调用查询纳税人信息接口{}出错, 请求报文：{}, 错误信息：{}", sid, request, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        cn.hutool.json.JSONObject jsonObject = XML.toJSONObject(result.getResult());
        cn.hutool.json.JSONObject taxML = jsonObject.getJSONObject("taxML");
        NsrxxCxResponseVo nsrxxCxResponseVo = JSONObject.parseObject(taxML.toString(), new TypeReference<NsrxxCxResponseVo>() {});
        if (nsrxxCxResponseVo.getNsrjbxx() == null || StringUtils.isBlank(nsrxxCxResponseVo.getNsrjbxx().getNsrsbh())) {
            throw new JeecgBootException("根据登记序号查询不到纳税人信息");
        }
        return nsrxxCxResponseVo;
    }

    /**
     * 查询批准机构信息
     * @param sessionId
     * @param swjgDm
     * @param shxydm
     * @return
     */
    public DzswjBaseResponse<List<PzjgxxVo>> nsrxxPzjgxx(String sessionId, String swjgDm, String shxydm) {
        if (StringUtils.isNotBlank(swjgDm)) {
            swjgDm = "14400000000";
        }
        String sid = "SWZJ.HXZGCX.DJ.PZJGXX";
        String request = "{\"SHXYDM\":\""+shxydm+"\",\"NSRSBH\":\""+shxydm+"\"}";
        Result<String> result = dy(sessionId, sid, swjgDm, request);
        if (!result.isSuccess()) {
            log.error("调用查询纳税人批准机构信息接口{}出错, 请求报文：{}, 错误信息：{}", sid, request, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        DzswjBaseResponse<List<PzjgxxVo>> response = JSONObject.parseObject(result.getResult(), new TypeReference<DzswjBaseResponse<List<PzjgxxVo>>>() {});
        return response;
    }

    /**
     * 查询财务报表<br/>
     * 如果返回为空，则表示该期未申报。
     * @param sessionId
     * @param swjgDm
     * @param cwbbReqVo
     */
    public GsCwbbVo cwbb(String sessionId, String swjgDm, CwbbReqVo cwbbReqVo) {
        String sid = "Nfzh.GDDS.GZCX.getXgmqyData";
        String content = "<taxML>\n" +
                "    <dataType>CWBB</dataType>\n" +
                "    <djxh>" + cwbbReqVo.getDjxh() + "</djxh>\n" +
                "    <ssqq>" + cwbbReqVo.getSsqq() + "</ssqq>\n" +
                "    <ssqz>" + cwbbReqVo.getSsqz() + "</ssqz>\n" +
                "</taxML>";
        Result<String> result = dycwbb(sessionId, sid, swjgDm, content);
        if (!result.isSuccess()) {
            log.error("调用查询纳税人信息接口{}出错, 请求报文：{}, 错误信息：{}", sid, content, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        if ("".equals(result.getResult())) {
            //无数据
            return null;
        }
        cn.hutool.json.JSONObject jsonObject = XML.toJSONObject(result.getResult());
        //如果没有成功转成json对象,则抛出异常,可能因为财务报表未报送
        if (jsonObject == null || jsonObject.size() == 0) {
            if (StringUtils.isNotBlank(result.getResult()) && result.getResult().contains("该期财务报表未报送")) {
                //该期财务报表未报送
                return null;
            }
            log.error("调用财报接口返回错误：入参:{}, 出参：{}", content, result.getResult());
            throw new JeecgBootException(result.getResult());
        }
        cn.hutool.json.JSONObject cwbbJson = jsonObject.getJSONObject("taxML");
        GsCwbbVo gsCwbbVo = JSONObject.parseObject(cwbbJson.toString(), new TypeReference<GsCwbbVo>() {});
        return gsCwbbVo;
    }

    /**
     * 查询申报记录
     */
    public CxnsrysbjlResponseVo cxnsrysbjl(String sessionId, String swjgDm, CxnsrysbjlReqVo reqVo) {
        //查询申报记录
        String sid = "SWZJ.HXZG.SB.CXNSRYSBJL";
        String xml = "<taxML xsi:type=\"HXZGSB00065Request\" xmlbh=\"String\" bbh=\"String\" xmlmc=\"String\" xsi:schemaLocation=\"http://www.chinatax.gov.cn/dataspec/ TaxMLBw_HXZG_SB_00065_Request_V1.0.xsd\" xmlns=\"http://www.chinatax.gov.cn/dataspec/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
                "<sBCwgzCxVO>\n" +
                "\t\t<djxh>$djxh</djxh>\n" +
                "\t\t<skssqq>$skssqq</skssqq>\n" +
                "\t\t<skssqz>$skssqz</skssqz>\n" +
                "\t</sBCwgzCxVO>\n" +
                "</taxML>";
        String content = xml.replace("$djxh", reqVo.getDjxh())
                .replace("$skssqq", reqVo.getSkssqq())
                .replace("$skssqz", reqVo.getSkssqz());
        Result<String> result = dy(sessionId, sid, swjgDm, content);
        if (!result.isSuccess()) {
            log.error("调用查询申报记录接口{}出错, 请求报文：{}, 错误信息：{}", sid, content, result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        cn.hutool.json.JSONObject jsonObject = XML.toJSONObject(result.getResult());
        cn.hutool.json.JSONObject sbxxList = jsonObject.getJSONObject("taxML").getJSONObject("sbxxList");
        CxnsrysbjlResponseVo cxnsrysbjlResponseVo = JSONObject.parseObject(sbxxList.toString(), new TypeReference<CxnsrysbjlResponseVo>() {});
        return cxnsrysbjlResponseVo;
    }

    /**
     * 电子底账-发票详细信息查询（列表-不含货物明细）
     * @param sessionId
     * @param swjgDm
     * @param reqVo
     */
    @Deprecated
    public DzdzplFpxxcxResponseVo dzdzplfpxxxxcx(String sessionId, String swjgDm, DzdzplFpxxxxcxReqVo reqVo) {
        String sid = "00.FP.FPXX.DZSWJCX.DZDZPLFPXXXXCX";
        Result<String> result = dy(sessionId, sid, swjgDm, JSON.toJSONString(reqVo));
        if (!result.isSuccess()) {
            log.error("调用查询发票列表接口{}出错, 请求报文：{}, 错误信息：{}", sid, JSON.toJSONString(reqVo), result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        DzdzplFpxxcxResponseVo fpxxcx = JSONObject.parseObject(result.getResult(), new TypeReference<DzdzplFpxxcxResponseVo>(){});
        return fpxxcx;
    }

    /**
     * 查询发票清单
     * @param sessionId
     * @param swjgDm
     * @param reqVo
     */
    public DzdzqdcxVo dzdzfpqdcx(String sessionId, String swjgDm, DzdzqdcxReqVo reqVo) {
        String sid = "00.FP.FPXX.DZSWJCX.DZDZQDCX";

        String request = "";
        Result<String> result = dy(sessionId, sid, swjgDm, request);
        if (!result.isSuccess()) {
            log.error("调用查询发票清单接口{}出错, 请求报文：{}, 错误信息：{}", sid, JSON.toJSONString(reqVo), result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        String responseMw = result.getResult();
        try {
            String responeDecompress = ZIPUtil.decompress(responseMw, true);
            String decryptResponse = "";
            FpBaseResponse<DzdzqdcxVo> fpxxcx = JSONObject.parseObject(decryptResponse, new TypeReference<FpBaseResponse<DzdzqdcxVo>>(){});
            if (!"000".equals(fpxxcx.getHead().getCode())) {
                log.error("调用查询发票清单接口{}出错, 请求报文:{}, 返回:{}", sid, JSON.toJSONString(reqVo), JSON.toJSONString(fpxxcx));
            }
            return fpxxcx.getBody();
        } catch (Exception e) {
            log.error("调用查询发票清单接口{},返回报文解压出错, 请求报文:{}, 返回报文密文: {}", sid, JSON.toJSONString(reqVo), responseMw);
            throw new JeecgBootException("报文解压出错", e);
        }
    }

    /**
     * 查询发票详细(主表和货物明细)
     * @param sessionId
     * @param swjgDm
     * @param reqVo
     */
    public DzdzfpbccxVo dzdzfpbccx(String sessionId, String swjgDm, DzdzfpbccxReqVo reqVo) {
        String sid = "00.FP.FPXX.DZSWJCX.DZDZFPBCCX";

        String request = "";
        Result<String> result = dy(sessionId, sid, swjgDm, request);
        if (!result.isSuccess()) {
            log.error("调用查询发票详细接口{}出错, 请求报文：{}, 错误信息：{}", sid, JSON.toJSONString(reqVo), result.getMessage());
            throw new JeecgBootException(result.getMessage());
        }
        String responseMw = result.getResult();
        try {
            String responeDecompress = ZIPUtil.decompress(responseMw, true);
            String decryptResponse = "";
            FpBaseResponse<DzdzfpbccxVo> fpxxcx = JSONObject.parseObject(decryptResponse, new TypeReference<FpBaseResponse<DzdzfpbccxVo>>(){});
            if (!"000".equals(fpxxcx.getHead().getCode())) {
                log.error("调用查询发票详细接口{}出错, 请求报文:{}, 返回:{}", sid, JSON.toJSONString(reqVo), JSON.toJSONString(fpxxcx));
            }
            return fpxxcx.getBody();
        } catch (Exception e) {
            log.error("调用查询发票详细接口{},返回报文解压出错, 请求报文:{}, 返回报文密文: {}", sid, JSON.toJSONString(reqVo), responseMw);
            throw new JeecgBootException("报文解压出错", e);
        }
    }
}
